﻿namespace DistanceSensor.ViewModels;

using Avalonia;
using CSharedMemory;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using ReactiveUI;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Ports;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

public class MainViewModel : ViewModelBase
{
    private SerialPort serial = new SerialPort("COM4");
    private Queue<byte> ReadBuffer = new Queue<byte>();
    private int[] distances = new int[6];
    private double temp;
    private bool _Connected;
    private const int FrameSize = 18;
    private enum ParseState_T {
        WaitHead1,
        WaitHead2,
        WaitBody
    }
    private ParseState_T _ParseState = ParseState_T.WaitHead1;
    private System.Timers.Timer timer = new System.Timers.Timer(50);
    public int Distance1 => distances[0];
    public int Distance2 => distances[1];
    public int Distance3 => distances[2];
    public int Distance4 => distances[3];
    public int Distance5 => distances[4];
    public int Distance6 => distances[5];
    public double BodyTemp => temp;
    public bool Connected => _Connected;

    private void Parse()
    {
        if (_ParseState == ParseState_T.WaitHead1)
        {
            if (ReadBuffer.Count >= FrameSize)
            {
                byte c = ReadBuffer.Dequeue();
                if (c == 0x80)
                {
                    _ParseState = ParseState_T.WaitHead2;
                }
            }
        }

        if (_ParseState == ParseState_T.WaitHead2)
        {
            byte c = ReadBuffer.Dequeue();
            if (c == 0xAA)
            {
                _ParseState = ParseState_T.WaitBody;
            }
            else
            {
                _ParseState = ParseState_T.WaitHead1;
            }
        }

        if (_ParseState == ParseState_T.WaitBody)
        {
            byte[] b = new byte[FrameSize - 2];
            for (int i = 0; i < b.Length; i++)
            {
                b[i] = ReadBuffer.Dequeue();
            }
            for (int i = 0; i < distances.Length; i++)
            {
                distances[i] = (b[2 * i] << 8) + b[2 * i + 1];
            }
            temp = ((b[12] << 8) + b[13]) / 100.0;
            _ParseState = ParseState_T.WaitHead1;
        }
    }

    public MainViewModel()
    {
        timer.Elapsed += Timer_Elapsed;
        try
        {
            serial.BaudRate = 115200;
            serial.StopBits = StopBits.One;
            serial.Parity = Parity.None;
            serial.DataBits = 8;
            serial.Open();
            _Connected = true;
        }
        catch (System.Exception ex)
        {
            Console.WriteLine(ex.Message);
            _Connected = false;
        }

        if(Connected)
        {
            timer.Start();
            Task.Factory.StartNew(() =>
            {
                while(true)
                {
                    var len = serial.BytesToRead;
                    if (len >= FrameSize)
                    {
                        byte[] rd_data = new byte[len];
                        serial.Read(rd_data, 0, len);
                        foreach (byte d in rd_data)
                        {
                            ReadBuffer.Enqueue(d);
                        }                        
                    }
                    Thread.Sleep(1);
                }
            }, TaskCreationOptions.LongRunning);
            Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    Parse();
                    Thread.Sleep(1);
                }
            }, TaskCreationOptions.LongRunning);
        }
    }

    private void Timer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
    {
        this.RaisePropertyChanged(nameof(Distance1));
        this.RaisePropertyChanged(nameof(Distance2));
        this.RaisePropertyChanged(nameof(Distance3));
        this.RaisePropertyChanged(nameof(Distance4));
        this.RaisePropertyChanged(nameof(Distance5));
        this.RaisePropertyChanged(nameof(Distance6));
        this.RaisePropertyChanged(nameof(BodyTemp));

        //if(robotMemory.id++ == 1000)
        //robotMemory.id = 0;

        //CHelper.Instance.SetMemoryValue(robotMemory);
    }
}
